package no.gnet.edvd.types;

import java.util.List;

import no.gnet.edvd.statemachine.State;

import org.joda.time.DateTime;
import org.joda.time.Instant;
import org.joda.time.Interval;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

public abstract class Event extends Persist {

	/**
	 * 
	 */
	private static final long serialVersionUID = -8186978024203829239L;
	public String name;
	public String description;
	public Category category;
	public DateTime betDeadline;
	public DateTime eventDecidedTime;
	public DateTime eventPosted;
	public Player owner; // null for regular events
	public EventType eventType;
	public int likes;
	public List<Player> likers;
	public State state;
	public Option winningOption; 
	public double pot; 
	
	public abstract List<Option> getOptions();

	public abstract List<String> getInvitedList();
	
	public abstract Option getOptionByName(String name);

	public String getName() {
		return name;
	}

	public String getDescription() {
		return description;
	}

	public void setLikers(List<Player> likers) {
		this.likers = likers;
	}

	public int getLikes() {
		if (likers != null) {
			return likers.size();
		}
		return likes;
	}

	public String getDatePosted() {
		return readerFriendlyPeriod(eventPosted);
	}

	private String toReaderFriendlyTime(Interval interval, boolean future) {
		int delta = (int) (interval.toDurationMillis() / 1000);
		int minutes = interval.toPeriod().getMinutes();
		int hrs = interval.toPeriod().getHours();
		int days = interval.toPeriod().getDays();
		int months = interval.toPeriod().getMonths();
		int years = interval.toPeriod().getYears();

		if (future) {
			return getFutureFriendlyTime(delta, minutes, hrs, days, months,
					years);
		}

		if (delta < 60) {
			return delta == 1 ? "one second ago" : delta + " seconds ago";
		}
		if (delta < 120) {
			return "a minute ago";
		}
		if (delta < 2700) // 45 * 60
		{
			return minutes + " minutes ago";
		}
		if (delta < 5400) // 90 * 60
		{
			return "an hour ago";
		}
		if (delta < 86400) // 24 * 60 * 60
		{
			return hrs + " hours ago";
		}
		if (delta < 172800) // 48 * 60 * 60
		{
			return "yesterday";
		}
		if (delta < 2592000) // 30 * 24 * 60 * 60
		{
			return days + " days ago";
		}
		if (delta < 31104000) // 12 * 30 * 24 * 60 * 60
		{
			return months <= 1 ? "one month ago" : months + " months ago";
		}
		return years <= 1 ? "one year ago" : years + " years ago";
	}

	private String getFutureFriendlyTime(int delta, int minutes, int hrs,
			int days, int months, int years) {
		if (delta < 60) {
			return delta == 1 ? "in one second" : "in " + delta + " seconds ";
		}
		if (delta < 120) {
			return "in a minute";
		}
		if (delta < 2700) // 45 * 60
		{
			return "in " + minutes + " minutes";
		}
		if (delta < 5400) // 90 * 60
		{
			return "in an hour";
		}
		if (delta < 86400) // 24 * 60 * 60
		{
			return "in " + hrs + " hours";
		}
		if (delta < 172800) // 48 * 60 * 60
		{
			return "tomorrow";
		}
		if (delta < 2592000) // 30 * 24 * 60 * 60
		{
			return "in " + days + " days";
		}
		if (delta < 31104000) // 12 * 30 * 24 * 60 * 60
		{
			return months <= 1 ? "in one month" : "in " + months + "";
		}
		return years <= 1 ? "in one year" : "in " + years + " years";
	}

	public String getFormattedEventDecidedTime() {
		DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MMMM-dd HH:mm");
		return fmt.print(eventDecidedTime);
	}

	public String getFormattedBetDeadline() {
		DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MMMM-dd HH:mm");
		return fmt.print(betDeadline);
	}

	public String getReaderFriendlyEventDecidedTime() {
		return readerFriendlyPeriod(eventDecidedTime);
	}

	public String getReaderFriendlyBetDeadline() {
		return readerFriendlyPeriod(betDeadline);
	}

	private String readerFriendlyPeriod(DateTime dtime) {
		if(dtime==null)
			return "N/A";
		Instant now = new Instant();
		Interval interval = null;
		String readerFriendlyTime = null;		
		if (dtime.compareTo(now) < 0) {
			interval = new Interval(dtime, now);
			readerFriendlyTime = toReaderFriendlyTime(interval, false);
		} else {
			interval = new Interval(now, dtime);
			readerFriendlyTime = toReaderFriendlyTime(interval, true);
		}
		return readerFriendlyTime;
	}

	public Category getCategory() {
		return category;
	}

	public DateTime getBetDeadline() {
		return betDeadline;
	}

	public DateTime getEventDecidedTime() {
		return eventDecidedTime;
	}

	public DateTime getEventPosted() {
		return eventPosted;
	}

	public Player getOwner() {
		return owner;
	}

	public State getState() {
		return state;
	}

	public void setState(State state) {
		this.state = state;
	}

	public Option getWinningOption() {
		return winningOption;
	}

	public void setWinningOption(Option winningOption) {
		this.winningOption = winningOption;
	}

	public double getPot() {
		return pot;
	}

	public void setPot(double pot) {
		this.pot = pot;
	}

	public abstract boolean isPrivate() ;

}
